package edu.ssm.campusAssistant.utils;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 标题: 应用层工具类
 * </p>
 */
public class ApplicationUtils {

    private static Logger logger = LoggerFactory.getLogger(ApplicationUtils.class);
    private final static boolean isdebugEnabled = logger.isDebugEnabled();

    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private static ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 将前台的json字符串封装成对象
     *
     * @param request
     * @param interfaceType
     * @param method
     * @return
     */
    public static Object[] parameterConversion(HttpServletRequest request, String interfaceType, String method) {

        String reqParam = null;
        try {
            BufferedReader streamReader = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
            StringBuilder responseStrBuilder = new StringBuilder();
            String inputStr;
            while ((inputStr = streamReader.readLine()) != null)
                responseStrBuilder.append(inputStr);
            JSONObject jsonObject = JSONObject.fromObject(responseStrBuilder.toString());
            reqParam = initReqJsonStr(jsonObject, request);
        } catch (Exception e) {
            logger.error("请求数据出错", e);
            throw new RuntimeException("请求数据出错", e);
        }
        if (isdebugEnabled) {
            logger.debug("将前台的参数封装开始");
            logger.debug("interfaceType == " + interfaceType);
            logger.debug("method == " + method);
        }
        Object[] objs = null;
        try {
            // 获取接口类型
            Class<?> c = Class.forName(interfaceType);
            Method[] methods = c.getMethods();
            for (Method m : methods) {
                logger.debug("获取Method.getName = " + m.getName());
                if (method.equals(m.getName())) {
                    Class<?>[] ct = m.getParameterTypes();
                    if (ct.length > 0) {
                        // 实例化对应个数的object数组对象
                        objs = new Object[ct.length];
                        int i = 0;
                        for (Class<?> class1 : ct) {
                            logger.debug("class1 = " + class1.toString());
                            ObjectMapper mapper = new ObjectMapper();
                            mapper = mapper.setDateFormat(sdf);
                            logger.debug("obj:" + mapper.readValue(reqParam, class1));
                            objs[i] = mapper.readValue(reqParam, class1);
                            i++;
                        }
                    }
                    break;
                }
            }

        } catch (ClassNotFoundException e) {
            logger.error("接口类型定义错误", e);
            throw new RuntimeException("接口类型定义错误", e);
        } catch (Exception e) {
            logger.error("将前台的参数封装失败", e);
            throw new RuntimeException("将前台的参数封装失败", e);
        }
        return objs;
    }

    /**
     * 将前台的表单对象封装成对象
     *
     * @param request
     * @param interfaceType
     * @param method
     * @return
     */
    public static Object[] parameterConversion2(HttpServletRequest request, String interfaceType, String method) {
        if (isdebugEnabled) {
            logger.debug("将前台的参数封装开始");
            logger.debug("interfaceType == " + interfaceType);
            logger.debug("method == " + method);
        }
        Object parameterObjs[] = null;
        try {
            logger.debug("获取接口类型开始");
            // 获取接口类型
            Class<?> c = Class.forName(interfaceType);
            Method[] methods = c.getMethods();
            for (Method m : methods) {
                if (method.equals(m.getName())) {
                    Class<?> parameterTypeClasses[] = m.getParameterTypes();
                    if (parameterTypeClasses != null && parameterTypeClasses.length > 0) {
                        // 转换请求参数到对应的参数类型中
                        parameterObjs = new Object[parameterTypeClasses.length];
                        for (int i = 0; i < parameterTypeClasses.length; i++) {
                            Object parameterObj = requestParameterHandler(request, parameterTypeClasses[i]);
                            parameterObjs[i] = parameterObj;
                        }
                    }
                    break;
                }
            }
            if (isdebugEnabled) {
                logger.debug("获取接口类型结束");
            }
        } catch (ClassNotFoundException e) {
            logger.error("接口类型定义错误", e);
            throw new RuntimeException("接口类型定义错误", e);
        } catch (Exception e) {
            logger.error("将前台的参数封装失败", e);
            throw new RuntimeException("将前台的参数封装失败", e);
        }
        return parameterObjs;
    }

    /**
     * javaBean转map
     *
     * @param obj
     * @return
     */
    public static Map<String, Object> transBean2Map(Object obj) {
        if (obj == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<String, Object>();
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();
                // 过滤class属性
                if (!key.equals("class")) {
                    // 得到property对应的getter方法
                    Method getter = property.getReadMethod();
                    Object value = getter.invoke(obj);
                    map.put(key, value);
                }
            }
        } catch (Exception e) {
            logger.error("javaBean转map错误", e);
            throw new RuntimeException("javaBean转map错误", e);
        }
        return map;
    }

    /**
     * 将值赋值给属性
     *
     * @param request
     * @param parameterTypeClass
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws NoSuchFieldException
     * @throws SecurityException
     * @throws JsonParseException
     * @throws JsonMappingException
     * @throws IOException
     */
    public static Object requestParameterHandler(HttpServletRequest request, Class<?> parameterTypeClass)
            throws InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException, JsonParseException, JsonMappingException, IOException {
        Object parameterObj = null;
        ConvertJson annotationConvertJson = parameterTypeClass.getAnnotation(ConvertJson.class);
        if (annotationConvertJson != null) {
            String jsonName = annotationConvertJson.value();
            if (StringUtils.isBlank(jsonName)) {
                jsonName = toLowerCaseFirst(parameterTypeClass.getSimpleName());
            }
            String jsonValue = request.getParameter(jsonName);
            if (StringUtils.isNotBlank(jsonValue)) {
                JSONObject jsonObject = JSONObject.fromObject(jsonValue);
                parameterObj = JSONObject.toBean(jsonObject, parameterTypeClass);
            }
        } else {
            /* 获取所有的Field */
            List<Field> fieldList = null;
            parameterObj = parameterTypeClass.newInstance();

            fieldList = getDeclaredField(parameterTypeClass, Object.class);

            for (Field field : fieldList) {
                ConvertJson annotationField = field.getAnnotation(ConvertJson.class);

                field.setAccessible(true);
                if (annotationField != null) {
                    String fieldJsonName = annotationField.value();
                    if (StringUtils.isBlank(fieldJsonName)) {
                        fieldJsonName = toLowerCaseFirst(field.getName());
                    }
                    String fieldJsonValue = request.getParameter(fieldJsonName);

                    if (StringUtils.isNotBlank(fieldJsonValue)) {
                        Class<?> fieldClass = field.getType();
                        if (fieldClass.isAssignableFrom(List.class)) {
                            Type fieldType = field.getGenericType();
                            if (fieldType instanceof ParameterizedType) {
                                ParameterizedType parameterizedType = (ParameterizedType) fieldType;
                                Class<?> fieldParameterzedTypeClass = (Class<?>) parameterizedType.getActualTypeArguments()[0];
                                JSONObject jsonObject = JSONObject.fromObject(fieldJsonValue);
                                Object fieldObject = JSONObject.toBean(jsonObject, fieldParameterzedTypeClass);

                                field.set(parameterObj, fieldObject);
                            }
                        } else {
                            objectMapper = objectMapper.setDateFormat(sdf);
                            Object fieldObject = objectMapper.readValue(fieldJsonValue, fieldClass);
                            field.set(parameterObj, fieldObject);
                        }
                    }
                } else {
                    String fieldValue = request.getParameter(field.getName());
                    if (StringUtils.isNotBlank(fieldValue)) {
                        field.set(parameterObj, convertDataType(fieldValue, field));
                    }
                }
            }
        }
        return parameterObj;
    }


    /**
     * 将字符串第一个字符转换为小写
     *
     * @param str
     * @return
     */
    public static String toLowerCaseFirst(String str) {
        if (Character.isLowerCase(str.charAt(0))) {
            return str;
        } else {
            return (new StringBuilder()).append(Character.toLowerCase(str.charAt(0))).append(str.substring(1)).toString();
        }
    }

    /**
     * 获取参数下所有字段，静态的除外
     *
     * @param c
     * @return
     */
    public static List<Field> getDeclaredField(Class<?> c, Class<?> stopClass) {
        List<Field> list = new ArrayList<>();
        for (; c != stopClass; c = c.getSuperclass()) {
            Field fields[] = c.getDeclaredFields();
            for (Field field : fields) {
                if (!Modifier.isStatic(field.getModifiers())) {
                    list.add(field);
                }
            }
        }

        return list;
    }

    /**
     * 数据类型转换
     *
     * @param value
     * @param field
     * @return
     */
    public static Object convertDataType(String value, Field field) {
        Object convertValue = null;
        Class<?> fieldTypeClass = field.getType();
        if (fieldTypeClass.isAssignableFrom(value.getClass())) {
            convertValue = value;
        } else {
            convertValue = GeneralHelper.str2Object(fieldTypeClass, value);
        }

        return convertValue;
    }

    /**
     * 存放HttpSession信息
     *
     * @param jsonObject
     * @return
     */
    private static String initReqJsonStr(JSONObject jsonObject, HttpServletRequest request) {
//        HttpSession session = request.getSession();
//        jsonObject.put("validateCode", session.getAttribute("validateCode"));
//        jsonObject.put("phoneCode", session.getAttribute("phoneCode"));
        return jsonObject.toString();
    }

    /**
     * 存放HttpSession信息
     *
     * @param request
     * @return
     */
    public static ParameterRequestWrapper packageRequestParameters(HttpServletRequest request) {
        ParameterRequestWrapper requestWrapper = new ParameterRequestWrapper(request);
//        HttpSession session = request.getSession();
//        requestWrapper.addParameter("validateCode", session.getAttribute("validateCode"));
//        requestWrapper.addParameter("phoneCode", session.getAttribute("phoneCode"));
        return requestWrapper;
    }
}
